class Counters {
  constructor (public count: number = 0) {}
  public add (value: number) {
    this.count += value
    return this  // 返回this的作用可以实现链式调用
  }
  public subtract(value: number) {
    this.count -= value
    return this
  }
}
let counter1 = new Counters(10)
// console.log(counter1.add(3).subtract(2));

class PowCounter extends Counters {
  constructor (public count: number = 0) {
    super(count)
  }
  public pow(value: number) {
    this.count = this.count ** value
    return this
  }
}

let powCounter = new PowCounter(2)
// console.log(powCounter.pow(3).add(2).subtract(3));

// 索引操作符 keyof

function getValue<T, K extends keyof T>(obj: T, name: K[]): Array<T[K]>{
  return name.map((n) => obj[n])
}

const infoObj = {
  name: 'lison',
  age: 18
}
let infoValues: Array<string | number> = getValue(infoObj, ['name', 'age'])
// console.log(infoValues);

// [] 索引访问操作符
interface InfoInterFaceAdvanced {
  name: string;
  age: number
}

type NameTypes = InfoInterFaceAdvanced['name']

function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
  return o[name]
}

interface Objs<T> {
  [key: string] : T
}

const obj1: Objs<number> ={
  age: 18
}
let keys: keyof Objs<number>

interface Type {
  a: never;
  b: string;
  c: number;
  d: undefined;
  e: null;
  f: object;
}

type Test = Type[keyof Type]  // 把 never过滤掉了

// 映射类型
interface Info1 {
  age: number;
  name: string;
  sex: string;
}

type ReadonlyType<T> = {
  // readonly [P in keyof T]: T[P]
  readonly [P in keyof T]?: T[P]  // 可以用+   + readonly [P in keyof T]?: T[P]
} // 相当于一个赋值函数


type RemoveReadonlyType<T> = {
  // readonly [P in keyof T]: T[P]
  -readonly [P in keyof T]-?: T[P]  // 可以用+   + readonly [P in keyof T]?: T[P]
}

// type ReadonlyType1 = ReadonlyType<Info1>  // 把Info1的值赋给ReadonlyType1
type ReadonlyType1 = Readonly<Info1> // 等同于上面的操作
type ReadonlyType3 = ReadonlyType<Info1> 

type ReadonlyType2 = RemoveReadonlyType<Info1>

let info11: ReadonlyType1 = {
  age: 18,
  name: 'lison',
  sex: 'man'
}

// info11.age = 30

// *Readonly Partial  可以直接使用   Partial// 可选属性，  Readonly// 只读属性
// Pick,  Record 

interface Info2 {
  name: string;
  age: number;
  address: string;
}

const info5: Info2 = {
  name: 'lison',
  age: 18,
  address: 'beijing'
}

function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  const res: any = {}
  keys.map((key) => {
    res[key] = obj[key]
  })
  return res
}

const nameAndAddress = pick(info5, ['name', 'age'])
// console.log(nameAndAddress);

function mapObject<K extends string | number, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U> {
  const res: any = {}
  for (const key in obj) {
    res[key] = f(obj[key])
  }
  return res
}

const names = { 0: 'hello', 1: 'world', 2: 'bye'}
const lengths = mapObject(names, (s) => s.length)

// console.log(lengths);

type Proxy<T> = {
  get(): T;
  set(value: T): void;
}

type Proxify<T> = {
  [P in keyof T]: Proxy<T[P]>
}

function proxify<T>(obj: T): Proxify<T> {
  const result = {} as Proxify<T>
  for(const key in obj) {
    result[key] = {
      get: ()=> obj[key],
      set: (value) => obj[key] = value
    }
  }
  return result
}

let props = {
  name: 'lison',
  age: 18
}

let proxyProps = proxify(props)
proxyProps.name.set('li')
// console.log(proxyProps.name.get());

function unproxify<T>(t: Proxify<T>): T {
  const result = {} as T
  for (const k in t) {
    result[k] = t[k].get()
  }
  return result
}

let originalProps = unproxify(proxyProps)
// console.log(originalProps);


const stringIndex = 'a'
const numberIndex = 1
const symbolIndex = Symbol()

type Obj2 = {
  [stringIndex]: string;
  [numberIndex]: number;
  [symbolIndex]: symbol;
}

type keysType = keyof Obj2
type ReadonlyTypes<T> = {
  readonly [P in keyof T]: T[P]
}
let Objs3: ReadonlyTypes<Obj2> = {
  a: 'aa',
  1: 11,
  [symbolIndex]: Symbol()
}

// Objs3.a = 'bb'

type MapToPromise<T> = {
  [K in keyof T]: Promise<T[K]>
}

type Tuple = [number, string, boolean]
type promiseTuple = MapToPromise<Tuple>
let tuple1: promiseTuple = [
  new Promise((resolve, reject) => resolve(1)),
  new Promise((resolve, reject) => resolve('a')),
  new Promise((resolve, reject) => resolve(false)),
]


// unknown 顶级类型
// 1 任何类型都可以赋值给unknown 类型
let value1: unknown
value1 = 'a'
value1 = 1

// 2 如果没有类型断言或基于控制流的类型细化时，unknown不可以赋值给其他类型， 此时他智能赋值给unknown和any类型

let value2: unknown
// let value3: string = value2
value1 = value2

// 3 如果没有类型断言或基于控制流的类型细化时， 不能在他上面进行任何操作
let value4: unknown
// value4 += 1

// 4 unknown与任何其他类型组成的交叉类型，最后都等于其他类型
type type1 = string & unknown
type type2 = number & unknown
type type3 = unknown & unknown
type type4 = unknown & string[]

// 5 unknown与任何其他类型（除了any）组成的联合类型，都等于unknown类型
type type5 = unknown | string
type type6 = any | unknown
type type7 = number[] | unknown

// 6 never类型unknown的子类型
type type8 = never extends unknown ? true : false

// 7 keyof unknown 等于类型never
type type9 = keyof unknown

// 8 智能对unknown进行等或不等操作，不能进行其他操作
value1 === value2
value1 !== value2
// value1 += value2

// 9 unknown类型的值不能访问他的属性，作为函数调用和作为类创建实例
let value10: unknown
// value10.age
// value10()
// new value10()

// 10 使用映射类型时如果遍历的是unknown类型，则不会映射任何属性
type Types1<T> = {
  [P in keyof T]: number
}
type type11 = Types1<any>
type type12 = Types1<unknown>

// 条件类型 T extends U ? X : Y

type Types2<T> = T extends string ? string : number
// let index: Types2<'a'>

type TypeName<T> = T extends any ? T : never
type Type3 = TypeName<string | number>

type TypeName1<T> = 
  T extends string ? string : 
  T extends number ? number :
  T extends boolean ? boolean :
  T extends undefined ? undefined :
  T extends () => void ? () => void :
  object

  type Type4 = TypeName1<() => void>
  type Type5 = TypeName1<string[]>
  type Type6 = TypeName1<() => void | string[]>

  type Diff<T, U> = T extends U ? never : T
  type Test2 = Diff<string | number | boolean, undefined | number>

  type Type7<T> = {
    [K in keyof T ]: T[K] extends Function ? K : never
  }[keyof T] // [keyof T] 返回类型不为never的属性名

  interface Part {
    id: number;
    name: string;
    //subparts: Part[];
    subparts(newName: string): void
    undatePart(newName: string): void
  }

  type Test1 = Type7<Part>

  // infer 类型推断
  type Type8<T> = T extends any[] ? T[number] : T
 
  type Test3 = Type8<string[]>
  type Test4= Type8<['aa', 123]>

  type Type9<T> = T extends Array<infer U> ? U : T
  type Test5 = Type9<string[]>
  type Test6 = Type9<number[]>
  type Test7 = Type9<number>

  // Exlude<T, U> 从T中排除可分配给U的那些类型
  type Type10 = Exclude<'a' | 'b' | 'c', 'a'>

  // Extract<T, U> 取出U类型
  type Type11 = Extract<'a' | 'b' | 'c', 'b' | 'c'>

  // NonNullable<T> 过滤掉null， undefined
  type Type12 = NonNullable<string | number | null | undefined>

  // ReturnType<T>
  type Type13 = ReturnType<() => string>
  type Type14 = ReturnType<() => void>

// InstanceType<T>
class Aclass {
  constructor() {}
}

type T1 = InstanceType<typeof Aclass>
